package constructdata;

import codetree.CodeTree;
import codetree.CodeTreeOperation;
import codetree.TreeNode;

import java.io.FileWriter;
import java.util.LinkedList;
import java.util.List;

/**
 * Termination Training Data Construction
 * Created by wangxin on 13/07/2017.
 */
public class ConstructTerminationData4 {
    // The marks
    private final String TERMMARK = "termination";

    // The maximum hole number of the continuous holes
    private int MAX_HOLENUM = 5;
    // The construct trees
    private LinkedList<CodeTree> trees;
    // The predication holes correspondent to the constructTrees;
    private LinkedList<String> predictions;
    // The predicate node's complete class name
    private LinkedList<String> classnames;
    // The node who is the parent of the predicated one
    private LinkedList<TreeNode> parents;
    // CodeTreeOperator
    private CodeTreeOperation operator;
    // The size of hole
    private  LinkedList<String> holesizes;
    // The block predictions
    private LinkedList<String> blockpredictions;
    private String blockprediction;
    // The original statements
    private LinkedList<String> originalStatements;
    // The variable names
    private LinkedList<String> variableNames;
    private String label = null;

    /**
     * Constructor
     * */
    public ConstructTerminationData4(String label){
        operator = new CodeTreeOperation();
        this.label = label;
    }

    public void construct(CodeTree tree,
                          FileWriter treeWriter,FileWriter predictionWriter,FileWriter classWriter, FileWriter generationNodeWriter,FileWriter treeSentenceWriter, FileWriter jarWriter, FileWriter holeSizeWriter,
                          FileWriter traceWriter, // trace back
                          FileWriter blockpredictionWriter, // block of predictions (more lines)
                          FileWriter originalStatementsWriter, // original statements
                          FileWriter variableNamesWriter,// variable names
                          FileWriter linesWriter,// lines writer
                          boolean isCompleteFlag){
        LinkedList<LinkedList> result = getConstructTrainingData(tree);
        List<CodeTree> treeList = result.get(0);
        List<String> predictionList = result.get(1);
        List<String> classList = result.get(2);
        List<TreeNode> generationNodeList = result.get(3);
        List<String> holeSizeList = result.get(4);// record size of hole
        List<String> blockpredictionList = result.get(5);
        List<String> originalStatementsList = result.get(6);
        List<String> variableNameList = result.get(7);

        //FindJarHandler findJarHandler = new FindJarHandler();
        for (int i = 0; i < treeList.size(); i++) {
            try {
                //String jar = findJarHandler.getPackage(classList.get(i));
                //if(jar != null) {
                CodeTree tempTree = treeList.get(i);
                operator.saveRegularizedTreeInFile(operator.regularization(tempTree), treeWriter);
                operator.saveTrainingPredictionInFile(label, predictionWriter);
                operator.saveTrainingPredictionInFile(label, classWriter);
                //operator.saveTrainingPredictionInFile(jar, jarWriter);
                int parentnum = generationNodeList.get(i).getSerialNumber();
                operator.saveTrainingPredictionInFile(parentnum + " " + ((parentnum != 0) ? generationNodeList.get(i).getCompleteMethodDeclaration() : ""), generationNodeWriter);
                operator.saveTreeStringFormatInFile(tempTree, treeSentenceWriter, isCompleteFlag);

                operator.saveTrainingPredictionInFile(holeSizeList.get(i), holeSizeWriter);

                operator.saveTrainingPredictionInFile(tree.getFunctionTrace(), traceWriter);
                operator.saveTrainingPredictionInFile(blockpredictionList.get(i), blockpredictionWriter);

                operator.saveTrainingPredictionInFile(originalStatementsList.get(i), originalStatementsWriter);
                operator.saveTrainingPredictionInFile(variableNameList.get(i), variableNamesWriter);

                operator.saveTrainingPredictionInFile((tempTree.getLines(tempTree.getRoot()) + 1)+"",linesWriter);

                //}
            } catch (Exception e) {
                System.err.println(e.getMessage());
            } catch (Error e){
                System.err.println(e.getMessage());
            }
        }
    }


    /**
     * Construct training tree from the input code tree
     * */
    public LinkedList<LinkedList> getConstructTrainingData(CodeTree completeTree){
        // Init
        trees = new LinkedList<>();
        predictions = new LinkedList<>();
        classnames = new LinkedList<>();
        parents = new LinkedList<>();
        holesizes = new LinkedList<>();
        blockpredictions = new LinkedList<>();

        originalStatements = new LinkedList<>();
        variableNames = new LinkedList<>();

        // Construct

//        int count = completeTree.getTotalNumber();
//        for (int i = 2; i <= count; i++) {// construct from the second node
//            construct(completeTree, i);
//        }

        int count = 1;
        for (int i = 1; i <= 1; i++) {// construct from the first node, construct once
            construct(completeTree, i);
        }

        // Return
        LinkedList<LinkedList> result = new LinkedList<>();
        result.addLast(trees);
        result.addLast(predictions);
        result.addLast(classnames);
        result.addLast(parents);
        result.addLast(holesizes);
        result.addLast(blockpredictions);
        result.addLast(originalStatements);
        result.addLast(variableNames);

        return result;
    }

    /**
     * @param completeTree: training data from this tree
     * @param serialNumber: node to construct termination mark with this serial number
     * */
    private void construct(CodeTree completeTree, int serialNumber){
        // Make the replica of the completeTree to avoid destroying.
        CodeTree tree = new CodeTree();
        tree.copyCodeTree(completeTree);
        operator.setSerialNumberofEachNode(tree);

        // Initialize the blockprediction
        blockprediction  = "";

        if(tree.getTotalNumber() >= serialNumber){
            boolean isSuccess = true;
            TreeNode node = tree.getTreeNode(serialNumber);
//            if(tree.getTotalNumber() == 1){// root node.
//                isSuccess = false;
//            }
//            else if(node.isCondition() // condition structure and conditions
//                    || node.isControl()// if, else, elseif, for, foreach, while, switch
//                    || label.equals("try")
//                    || label.equals("catch")
//                    || label.equals("condition")
//                    ){
//                isSuccess = false;
//            }
//            if(isSuccess){
            predictions.addLast(TERMMARK);
            trees.addLast(tree);
            classnames.addLast(TERMMARK);
            parents.addLast(node);
//            addHole(tree, node);
            holesizes.addLast("" + 0);
            blockpredictions.addLast(blockprediction);
            originalStatements.addLast(node.getStatement());
            List<String> previousVariableNames = node.getPreviousVariableNames();
            String variablename = previousVariableNames.size()>0?previousVariableNames.get(0):"";
            for (int i = 1; i < previousVariableNames.size(); i++) {
                variablename += " " + previousVariableNames.get(i);
            }
            variableNames.addLast(variablename);
//            }
        }
    }

//    private void addHole(CodeTree tree, TreeNode generationNode) {
//        TreeNode hole = new TreeNode();
//        hole.setClassName("hole");
//        hole.setCompleteClassName("hole");
//        hole.setMethodName("");
//        hole.setCompleteMethodName("");
//        hole.setAddMethodName(false);
//        tree.addNode(tree.getTreeNode(generationNode.getSerialNumber()), hole);
//        operator.setSerialNumberofEachNode(tree);
//    }
}
